﻿
using Furion.DataEncryption;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Magic.Core.Entity;
using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MiniExcelLibs;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Yitter.IdGenerator;

namespace Magic.Core.Service
{
    /// <summary>
    /// 用户服务
    /// </summary>
    [ApiDescriptionSettings(Name = "User", Order = 150)]
    public class SysUserService : ISysUserService, IDynamicApiController, ITransient
    {
        private readonly ISqlSugarRepository<SysUser> _sysUserRep;  // 用户表仓储 
        private readonly IUserManager _userManager;

        private readonly ISysCacheService _sysCacheService;
        private readonly ISysConfigService _sysConfigService;
        private readonly ISysEmpService _sysEmpService;
        private readonly ISysUserDataScopeService _sysUserDataScopeService;
        private readonly ISysUserRoleService _sysUserRoleService;
        private readonly ISysOrgService _sysOrgService;

        public SysUserService(ISqlSugarRepository<SysUser> sysUserRep,
                              IUserManager userManager,
                              ISysCacheService sysCacheService,
                              ISysEmpService sysEmpService,
                              ISysUserDataScopeService sysUserDataScopeService,
                              ISysUserRoleService sysUserRoleService,
                              ISysOrgService sysOrgService,
                              ISysConfigService sysConfigService)
        {
            _sysUserRep = sysUserRep;
            _userManager = userManager;
            _sysCacheService = sysCacheService;
            _sysEmpService = sysEmpService;
            _sysUserDataScopeService = sysUserDataScopeService;
            _sysUserRoleService = sysUserRoleService;
            _sysOrgService = sysOrgService;
            _sysConfigService = sysConfigService;
        }

        /// <summary>
        /// 分页查询用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("/sysUser/page")]
        public async Task<dynamic> QueryUserPageList([FromQuery] UserInput input)
        {
            var superAdmin = _userManager.SuperAdmin;
            var searchValue = input.SearchValue;
            var pid = input.SysEmpParam.OrgId;

            var dataScopes = await GetUserDataScopeIdList(_userManager.UserId);

            var users = await _sysUserRep.Context.Queryable<SysUser, SysEmp, SysOrg, SysTenant>((u, e, o,t) => new JoinQueryInfos(
                  JoinType.Inner, u.Id == e.Id,
                  JoinType.Inner, e.OrgId == o.Id,
                  JoinType.Inner, u.TenantId == t.Id
                  ))
                .WhereIF(!string.IsNullOrWhiteSpace(searchValue), (u, e, o) => u.Account.Contains(input.SearchValue.Trim()) ||
                                                                            u.Name.Contains(input.SearchValue.Trim()) ||
                                                                            u.Phone.Contains(input.SearchValue.Trim()))
                .WhereIF(!string.IsNullOrWhiteSpace(pid), (u, e, o) => e.OrgId == long.Parse(pid) ||
                                                                        o.Pids.Contains(pid.Trim()))
                .WhereIF(Enum.IsDefined(typeof(CommonStatus), input.SearchStatus), (u, e, o) => u.Status == input.SearchStatus)
                .WhereIF(!superAdmin, (u, e, o) => u.AdminType != AdminType.SuperAdmin)
                .WhereIF(!superAdmin && dataScopes.Any(), (u, e, o) => dataScopes.Contains(e.OrgId))
                .Select<UserOutput>("u.*,t.Name As TenantName ").ToPagedListAsync(input.PageNo, input.PageSize);

            foreach (var user in users.Items)
            {
                user.SysEmpInfo = await _sysEmpService.GetEmpInfo(long.Parse(user.Id));
            }
            return users.XnPagedResult();
        }

        /// <summary>
        /// 增加用户       
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysUser/add")]
        public async Task AddUser(AddUserInput input)
        {
            // 数据范围检查
            CheckDataScope(input.SysEmpParam == null || string.IsNullOrEmpty(input.SysEmpParam.OrgId) ? 0 : long.Parse(input.SysEmpParam.OrgId));

            var isExist = await _sysUserRep.AnyAsync(u => u.Account == input.Account);
            if (isExist) throw Oops.Oh(ErrorCode.D1003);

            var user = input.Adapt<SysUser>();
            user.Password = MD5Encryption.Encrypt(input.Password);
            if (string.IsNullOrEmpty(user.Name))
                user.Name = user.Account;
            if (string.IsNullOrEmpty(user.NickName))
                user.NickName = user.Account;

            try
            {
                _sysUserRep.Ado.BeginTran();
                var newUser = await _sysUserRep.Context.Insertable(user).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync();
                input.SysEmpParam.Id = newUser.Id.ToString();
                // 增加员工信息
                await _sysEmpService.AddOrUpdate(input.SysEmpParam);
                _sysUserRep.Ado.CommitTran();
            }
            catch (Exception)
            {
                _sysUserRep.Ado.RollbackTran();
                throw;
            }


        }

        /// <summary>
        /// 删除用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysUser/delete")]
        public async Task DeleteUser(DeleteUserInput input)
        {
            var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            if (user.AdminType == AdminType.SuperAdmin)
                throw Oops.Oh(ErrorCode.D1014);

            if (user.Account == _userManager.Account)
            {
                throw Oops.Oh(ErrorCode.D1001);
            }

            // 数据范围检查
            CheckDataScope(input.SysEmpParam == null || string.IsNullOrEmpty(input.SysEmpParam.OrgId) ? 0 : long.Parse(input.SysEmpParam.OrgId));

            try
            {
                _sysUserRep.Ado.BeginTran();
                // 直接删除用户
                await _sysUserRep.Context.Updateable(new SysUser {IsDeleted = true}).CallEntityMethod(m => m.Modify())
                    .UpdateColumns(user.FalseDeleteColumn()).Where(wh => wh.Id == user.Id).ExecuteCommandAsync();

                // 删除员工及附属机构职位信息
                await _sysEmpService.DeleteEmpInfoByUserId(user.Id);

                //删除该用户对应的用户-角色表关联信息
                await _sysUserRoleService.DeleteUserRoleListByUserId(user.Id);

                //删除该用户对应的用户-数据范围表关联信息
                await _sysUserDataScopeService.DeleteUserDataScopeListByUserId(user.Id);
                _sysUserRep.Ado.CommitTran();
            }
            catch (Exception)
            {
                _sysUserRep.Ado.RollbackTran();
                throw;
            }



        }

        /// <summary>
        /// 更新用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysUser/edit")]
        public async Task UpdateUser(UpdateUserInput input)
        {
            // 数据范围检查
            CheckDataScope(input.SysEmpParam == null || string.IsNullOrEmpty(input.SysEmpParam.OrgId) ? 0 : long.Parse(input.SysEmpParam.OrgId));

            // 排除自己并且判断与其他是否相同
            var isExist = await _sysUserRep.AnyAsync(u => u.Account == input.Account && u.Id != input.Id);
            if (isExist) throw Oops.Oh(ErrorCode.D1003);

            var user = input.Adapt<SysUser>();

            try
            {
                _sysUserRep.Ado.BeginTran();
                await _sysUserRep.Context.Updateable<SysUser>(user).IgnoreColumns(it => new { it.Password, it.Status, it.AdminType }).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.Modify()).ExecuteCommandAsync();
                input.SysEmpParam.Id = user.Id.ToString();
                // 更新员工及附属机构职位信息
                await _sysEmpService.AddOrUpdate(input.SysEmpParam);
                _sysUserRep.Ado.CommitTran();
            }
            catch (Exception)
            {
                _sysUserRep.Ado.RollbackTran();
                throw;
            }


        }

        /// <summary>
        /// 查看用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("/sysUser/detail")]
        public async Task<dynamic> GetUser([FromQuery] QueryUserInput input)
        {
            var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            var userDto = user.Adapt<UserOutput>();
            if (userDto != null)
            {
                userDto.SysEmpInfo = await _sysEmpService.GetEmpInfo(user.Id);
            }
            return userDto;
        }

        /// <summary>
        /// 修改用户状态
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysUser/changeStatus")]
        public async Task ChangeUserStatus(UpdateUserInput input)
        {
            var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            if (user.AdminType == AdminType.SuperAdmin)
                throw Oops.Oh(ErrorCode.D1015);

            if (!Enum.IsDefined(typeof(CommonStatus), input.Status))
                throw Oops.Oh(ErrorCode.D3005);
            user.Status = input.Status;
            await _sysUserRep.Context.Updateable(user).CallEntityMethod(m => m.Modify()).ExecuteCommandAsync();
        }

        /// <summary>
        /// 授权用户角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysUser/grantRole")]
        public async Task GrantUserRole(UpdateUserInput input)
        {
            // 数据范围检查
            CheckDataScope(input.SysEmpParam == null || string.IsNullOrEmpty(input.SysEmpParam.OrgId) ? 0 : long.Parse(input.SysEmpParam.OrgId));
            await _sysUserRoleService.GrantRole(input);
        }

        /// <summary>
        /// 授权用户数据范围
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysUser/grantData")]
        public async Task GrantUserData(UpdateUserInput input)
        {
            // 清除缓存
            await _sysCacheService.DelAsync(CommonConst.CACHE_KEY_DATASCOPE + $"{input.Id}");
            await _sysCacheService.DelAsync(CommonConst.CACHE_KEY_USERSDATASCOPE + $"{input.Id}");

            // 数据范围检查
            CheckDataScope(input.SysEmpParam == null || string.IsNullOrEmpty(input.SysEmpParam.OrgId) ? 0 : long.Parse(input.SysEmpParam.OrgId));
            await _sysUserDataScopeService.GrantData(input);
        }

        /// <summary>
        /// 更新用户信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysUser/updateInfo")]
        public async Task UpdateUserInfo(UpdateUserInput input)
        {
            var user = input.Adapt<SysUser>();
            await _sysUserRep.Context.Updateable<SysUser>(user)
                .CallEntityMethod(m => m.Modify())
                .IgnoreColumns(ignoreAllNullColumns: true)
                .IgnoreColumns(it => new { it.AdminType, it.LastLoginTime })
                .ExecuteCommandAsync();
        }

        /// <summary>
        /// 修改用户密码
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysUser/updatePwd")]
        public async Task UpdateUserPwd(ChangePasswordUserInput input)
        {
            var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            if (MD5Encryption.Encrypt(input.Password) != user.Password)
                throw Oops.Oh(ErrorCode.D1004);
            user.Password = MD5Encryption.Encrypt(input.NewPassword);
            await _sysUserRep.Context.Updateable<SysUser>(user).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.Modify()).ExecuteCommandAsync();
        }

        /// <summary>
        /// 获取用户拥有角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("/sysUser/ownRole")]
        public async Task<dynamic> GetUserOwnRole([FromQuery] QueryUserInput input)
        {
            return await _sysUserRoleService.GetUserRoleIdList(input.Id);
        }

        /// <summary>
        /// 获取用户拥有数据
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("/sysUser/ownData")]
        public async Task<dynamic> GetUserOwnData([FromQuery] QueryUserInput input)
        {
            return await _sysUserDataScopeService.GetUserDataScopeIdList(input.Id);
        }

        /// <summary>
        /// 重置用户密码
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysUser/resetPwd")]
        public async Task ResetUserPwd(QueryUserInput input)
        {
            var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            user.Password = MD5Encryption.Encrypt(await _sysConfigService.GetDefaultPassword());
            await _sysUserRep.Context.Updateable(user).IgnoreColumns(it => new { it.AdminType }).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.Modify()).ExecuteCommandAsync();
        }

        /// <summary>
        /// 修改用户头像
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("/sysUser/updateAvatar")]
        public async Task UpdateAvatar(UploadAvatarInput input)
        {
            var user = await _sysUserRep.FirstOrDefaultAsync(u => u.Id == input.Id);
            user.Avatar = input.Avatar.ToString();
            await _sysUserRep.Context.Updateable<SysUser>(user).IgnoreColumns(it => new { it.AdminType }).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.Modify()).ExecuteCommandAsync();
        }

        /// <summary>
        /// 获取用户选择器
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("/sysUser/selector")]
        public async Task<dynamic> GetUserSelector([FromQuery] UserInput input)
        {
            return await _sysUserRep.Context.Queryable<SysUser>()
                                   .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => (u.Name.Contains(input.Name.Trim())))
                                   .Where(u => u.Status != CommonStatus.DELETED)
                                   .Where(u => u.AdminType != AdminType.SuperAdmin)
                                   .Select(u => new
                                   {
                                       u.Id,
                                       u.Name
                                   }).ToListAsync();
        }

        /// <summary>
        /// 用户导出
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("/sysUser/export")]
        public async Task<IActionResult> ExportUser([FromQuery] UserInput input)
        {
            var users = await _sysUserRep.ToListAsync();

            var memoryStream = new MemoryStream();
            memoryStream.SaveAs(users);
            memoryStream.Seek(0, SeekOrigin.Begin);
            return await Task.FromResult(new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
            {
                FileDownloadName = "user.xlsx"
            });
        }

        /// <summary>
        /// 用户导入
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        [HttpPost("/sysUser/import")]
        public async Task ImportUser(IFormFile file)
        {
            var path = Path.Combine(Path.GetTempPath(), $"{YitIdHelper.NextId()}.xlsx");
            using (var stream = File.Create(path))
            {
                await file.CopyToAsync(stream);
            }

            //var rows = MiniExcel.Query(path); // 解析
            //foreach (var row in rows)
            //{
            //    var a = row.A;
            //    var b = row.B;
            //    // 入库等操作

            //}
        }

        /// <summary>
        /// 根据用户Id获取用户
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>       
        [NonAction]
        public async Task<dynamic> GetUserById(long userId)
        {
            return await _sysUserRep.FirstOrDefaultAsync(u => u.Id == userId);
        }

        /// <summary>
        /// 将OAuth账号转换成账号
        /// </summary>
        /// <param name="authUser"></param>
        /// <param name="sysUser"></param>
        /// <returns></returns>
        [NonAction]
        public async Task SaveAuthUserToUser(AuthUserInput authUser, UserInput sysUser)
        {
            var user = sysUser.Adapt<SysUser>();
            user.AdminType = AdminType.None; // 非管理员

            // oauth账号与系统账号判断
            var isExist = await _sysUserRep.AnyAsync(u => u.Account == authUser.Username);
            user.Account = isExist ? authUser.Username + DateTime.Now.Ticks : authUser.Username;
            user.Name = user.NickName = authUser.Nickname;
            user.Email = authUser.Email;
            user.Sex = authUser.Gender;
            await _sysUserRep.Context.Insertable(user).CallEntityMethod(m => m.Create()).ExecuteCommandAsync();
        }

        /// <summary>
        /// 获取用户数据范围（机构Id集合）并缓存
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>       
        [NonAction]
        public async Task<List<long>> GetUserDataScopeIdList(long userId = 0)
        {
            userId = userId <= 0 ? _userManager.UserId : userId;
            var dataScopes = await _sysCacheService.GetDataScope(userId); // 先从缓存里面读取
            if (dataScopes == null || dataScopes.Count < 1)
            {
                if (!_userManager.SuperAdmin)
                {
                    var orgId = await _sysEmpService.GetEmpOrgId(userId);
                    // 获取该用户对应的数据范围集合
                    var userDataScopeIdListForUser = await _sysUserDataScopeService.GetUserDataScopeIdList(userId);
                    // 获取该用户的角色对应的数据范围集合
                    var userDataScopeIdListForRole = await _sysUserRoleService.GetUserRoleDataScopeIdList(userId, orgId);
                    dataScopes = userDataScopeIdListForUser.Concat(userDataScopeIdListForRole).Distinct().ToList(); // 并集
                }
                else
                {
                    dataScopes = await _sysOrgService.GetAllDataScopeIdList();
                }
                await _sysCacheService.SetDataScope(userId, dataScopes); // 缓存结果
            }
            return dataScopes;
        }

        /// <summary>
        /// 检查普通用户数据范围
        /// </summary>
        /// <param name="orgId"></param>
        /// <returns></returns>
        [NonAction]
        public async void CheckDataScope(long orgId)
        {
            // 如果当前用户不是超级管理员，则进行数据范围校验
            if (!_userManager.SuperAdmin)
            {
                var dataScopes = await GetUserDataScopeIdList(_userManager.UserId);
                if (dataScopes == null ||orgId <= 0|| !dataScopes.Contains(orgId))
                    throw Oops.Oh(ErrorCode.D1013);
            }
        }
        /// <summary>
        /// 获取用户数据范围（用户Id集合）
        /// </summary>
        /// <returns></returns>
        [NonAction]
        public async Task<List<long>> GetDataScopeIdUserList(long userId = 0)
        {
            userId = userId<=0? _userManager.UserId: userId;
            var list = await _sysCacheService.GetUsersDataScope(userId); // 先从缓存里面读取
            if (list == null || list.Count < 1)
			{
                var dataScopes = await GetUserDataScopeIdList(userId);
                list = (await _sysEmpService.HasOrgEmp(dataScopes)).Select(a => a.Id).ToList();
                list.Add(userId);
                await _sysCacheService.SetUsersDataScope(userId, list.Distinct().ToList()); // 缓存结果
            }
            return list;
        }

        /// <summary>
        /// 检查普通用户数据范围
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        [NonAction]
        public async void CheckDataScopeByUserId(long userId)
        {
            // 如果当前用户不是超级管理员，则进行数据范围校验
            if (!_userManager.SuperAdmin)
            {
                var dataScopes = await GetDataScopeIdUserList(_userManager.UserId);
                if (dataScopes == null || userId <= 0 || !dataScopes.Contains(userId))
                    throw Oops.Oh(ErrorCode.D1013);
            }
        }
    }
}
